package com.lifang.framework.beans.factory.support;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.lifang.framework.beans.factory.PropertyValues;
import com.lifang.framework.beans.factory.config.ConfigurableBeanFactory;

import java.lang.reflect.Executable;

/**
 * bean 的定义
 * 包含class 属性等
 */
public class BeanDefinition {

    private Class<?> beanClass;

    private final PropertyValues propertyValues;

    private String beanClassName;

    private String initMethodName;

    private String destroyMethodName;

    private String scope = ConfigurableBeanFactory.SCOPE_SINGLETON;

    //构造函数是否已解析
    private boolean constructorArgumentsResolved = false;

    private Executable resolvedConstructorOrFactoryMethod;

    //构造函数参数
    private ConstructorArgumentValues constructorArgumentValues;

    public BeanDefinition(Class<?> beanClass) {
        this.beanClass = beanClass;
        this.propertyValues = new PropertyValues(beanClass);
    }

    public BeanDefinition(Class<?> beanClass, PropertyValues propertyValues) {
        Assert.notNull(beanClass, "beanClass must not be null");
        this.beanClass = beanClass;
        this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues(beanClass);
    }

    public Class<?> getBeanClass() {
        return beanClass;
    }

    public PropertyValues getPropertyValues() {
        return propertyValues;
    }

    public void setBeanClass(Class<?> beanClass) {
        this.beanClass = beanClass;
    }

    public String getInitMethodName() {
        return initMethodName;
    }

    public void setInitMethodName(String initMethodName) {
        this.initMethodName = initMethodName;
    }

    public String getDestroyMethodName() {
        return destroyMethodName;
    }

    public void setDestroyMethodName(String destroyMethodName) {
        this.destroyMethodName = destroyMethodName;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public boolean isSingleton() {
        return ConfigurableBeanFactory.SCOPE_SINGLETON.equals(this.scope);
    }

    public boolean isPrototype() {
        return ConfigurableBeanFactory.SCOPE_PROTOTYPE.equals(this.scope);
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

    public void addConstructorArgumentValue(String name, Object value) {
        if (this.constructorArgumentValues == null) {
            this.constructorArgumentValues = new ConstructorArgumentValues();
        }
        this.constructorArgumentValues.addConstructorValue(name, value);
    }

    public void addConstructorArgumentValue(Class<?> type, Object value) {
        if (this.constructorArgumentValues == null) {
            this.constructorArgumentValues = new ConstructorArgumentValues();
        }
        this.constructorArgumentValues.addConstructorValue(type, value);
    }

    public void addConstructorArgumentValue(Object value) {
        if (this.constructorArgumentValues == null) {
            this.constructorArgumentValues = new ConstructorArgumentValues();
        }
        this.constructorArgumentValues.addConstructorValue(value.getClass(), value);
    }

    public boolean hasConstructorArgument() {
        return this.constructorArgumentValues != null && !this.constructorArgumentValues.isEmpty();
    }

    public int getConstructorSize() {
        int size = 0;
        if (this.constructorArgumentValues != null) {
            size = Math.max(this.constructorArgumentValues.getConstructorValueSize(), size);
        }
        return size;
    }

    public Object getConstructorValue(int index, Class<?> type) {
        return this.constructorArgumentValues.getConstructorValue(index, type);
    }

    public String getBeanClassName() {
        return beanClassName;
    }

    public void setBeanClassName(String beanClassName) {
        this.beanClassName = beanClassName;
    }

    public void setConstructorArgumentsResolved(boolean constructorArgumentsResolved) {
        this.constructorArgumentsResolved = constructorArgumentsResolved;
    }

    public boolean isConstructorArgumentsResolved() {
        return constructorArgumentsResolved;
    }

    public Executable getResolvedConstructorOrFactoryMethod() {
        return resolvedConstructorOrFactoryMethod;
    }

    public void setResolvedConstructorOrFactoryMethod(Executable resolvedConstructorOrFactoryMethod) {
        this.resolvedConstructorOrFactoryMethod = resolvedConstructorOrFactoryMethod;
    }

    public boolean hasPropertyValues() {
        return this.propertyValues != null && CollectionUtil.isNotEmpty(this.propertyValues.getPropertyValues());
    }

}
